﻿using System;
using System.Linq;
using System.Web.Mvc;


namespace Kooboo.Web.Areas.Commerce.Controllers
{
    using Kooboo.Globalization;
    using Kooboo.Web.Mvc.Paging;
    using Kooboo.Commerce;
    using System.Data.Objects.DataClasses;


    using System.Collections.Generic;
    using Kooboo.IoC;
    using Kooboo.Web.Areas.Commerce.Web.UI;
    using Kooboo.Web.Areas.Commerce.Binders;
    using Kooboo.Web.Mvc;
    using Kooboo.Commerce.Contexts.Orders;
    using Kooboo.Commerce.Contexts.Shippings;
    using Kooboo.Commerce.Contexts.Countries;
    using Kooboo.Commerce.Contexts.Customers;
    using Kooboo.Commerce.Contexts.Payments;
    using Kooboo.Commerce.Contexts.Products;
    using System.Threading;
    using System.Web;



    public class OrderController : ManagementController
    {
        #region Index

        public ActionResult Index(int? page)
        {
            var pagedList = this.Actor
                .QueryOrders()
                .OrderByDescending(i => i.OrderDate)
                .ToPagedList(page ?? 1, Configuration.PageSize);

            return View(pagedList);
        }

        #endregion

        #region Search

        public ActionResult Search(int? page, int? orderId, DateTime? startDate,
                    DateTime? endDate, string emailAddress, int? orderStatusId)
        {
            var list = this.Actor.QueryOrders();

            if (!String.IsNullOrWhiteSpace(emailAddress))
            {
                list = list.Where(i => i.Customer.MailAddress == emailAddress);
            }

            if (orderId.HasValue)
            {
                list = list.Where(i => i.Id == orderId.Value);
            }

            if (orderStatusId.HasValue)
            {
                list = list.Where(i => i.OrderStatus == (OrderStatus)orderStatusId.Value);
            }

            if (startDate.HasValue)
            {
                list = list.Where(i => i.OrderDate >= startDate.Value);
            }

            if (endDate.HasValue)
            {
                list = list.Where(i => i.OrderDate <= endDate.Value);
            }

            var pageList = list.ToPagedList(page ?? 1, Configuration.PageSize);

            return View("Index", pageList);
        }

        #endregion

        #region Details

        public ActionResult Detail(int id)
        {
            var order = this.Actor
                .QueryOrders()
                .Where(i => i.Id == id)
                .FirstOrDefault();

            this.ViewData["ReturnUrl"] = Request["ReturnUrl"];

            ViewData["OrderStatus"] = this.BuildOrderStatus(order.OrderStatus);

            ViewData["Shippings"] = this.Actor.QueryShippings()
           .OrderBy(i => i.Name)
           .ToSelectableList(order.ShippingId);

            ViewData["Countries"] = this.Actor.QueryCountries()
                .ToSelectableList(order.Country);

            ViewData["InvoiceCountries"] = this.Actor.QueryCountries()
                .ToSelectableList(order.InvoiceCountry);

            String currentUrl = this.Request.Url.ToString();
            //fixed issue 832
            if (order.Customer == null)
            {
                ViewData["customer_view_action"] = string.Empty;// this.Url.Action("Edit", "Customer", new { id = UrlParameter<int>.Empty, returnUrl = currentUrl });
            }
            else
            {
                ViewData["customer_view_action"] = this.Url.Action("Edit", "Customer", new { id = order.Customer.Id, returnUrl = currentUrl });
            }


            return View(order);
        }
        IEnumerable<SelectListItem> BuildOrderStatus(OrderStatus status)
        {
            var names = Enum.GetNames(typeof(OrderStatus));
            var values = Enum.GetValues(typeof(OrderStatus));

            for (var i = 0; i < values.Length; i++)
            {
                var value = values.GetValue(i);
                var name = names[i];

                yield return new SelectListItem { Text = name, Value = ((int)value).ToString(), Selected = (int)status == (int)value };

            }
        }

        #endregion

        public ActionResult Create(string customers)
        {
            ViewData["calculate_action"] = this.Url.Action<OrderController>(i => i.Calculate(null));
            ViewData["search_customers_action"] = this.Url.Action<OrderController>(i => i.SearchCustomers(null));
            ViewData["search_products_action"] = this.Url.Action<OrderController>(i => i.SearchProducts(null));
            ViewData["search_customers_keyword"] = customers == null ? "" : customers;
            ViewData["customer_add_action"] = this.Url.Action<CustomerController>(i => i.Create(null));

            ViewData["OrderStatus"] = this.BuildOrderStatus(OrderStatus.PaymentPending);

            ViewData["customer_validator"] = ModelClientMetadataBuilder
                .BuildFor<ICustomer>(this.Url.Action<CustomerController>(i => i.Create(null)))
                .ValidateFor(i => i.City)
                .ValidateFor(i => i.Country)
                .ValidateFor(i => i.FirstName)
                .ValidateFor(i => i.LastName)
                .ValidateFor(i => i.MailAddress)
                //.ValidateFor(i => i.MiddleName)
                .ValidateFor(i => i.Mobile)
                .ValidateFor(i => i.Telphone)
                .ValidateFor(i => i.UserName)
                .ToMetadata();


            ViewData["order_validator"] = ModelClientMetadataBuilder
                .BuildFor<IOrder>(this.Url.Action<OrderController>(i => i.Create(null as IOrder)))
                .ValidateFor(i => i.Address1)
                .ValidateFor(i => i.Address2)
                .ValidateFor(i => i.City)
                .ValidateFor(i => i.Coupon)
                .ValidateFor(i => i.FirstName)
                .ValidateFor(i => i.InvoiceAddress1)
                .ValidateFor(i => i.InvoiceAddress2)
                .ValidateFor(i => i.InvoiceCity)
                .ValidateFor(i => i.InvoiceFirstName)
                .ValidateFor(i => i.InvoiceLastName)
                .ValidateFor(i => i.InvoicePhone)
                .ValidateFor(i => i.InvoicePostcode)
                .ValidateFor(i => i.InvoiceState)
                .ValidateFor(i => i.LastName)
                .ValidateFor(i => i.Phone)
                .ValidateFor(i => i.PaymentName)
                .ValidateFor(i => i.Phone)
                .ValidateFor(i => i.Postcode)
                .ValidateFor(i => i.Remark)
                .ValidateFor(i => i.ShippingTrackingCode)
                .ToMetadata();

            ViewData["Payments"] = this.Actor
                .QueryPayments()
                .Where(i => i.IsEnable)
                .OrderBy(i => i.MethodName)
                .Select(i => new SelectListItem
                {
                    Text = i.MethodName,
                    Value = i.MethodName
                })
                .AsEnumerable();


            ViewData["Shippings"] = this.Actor.QueryShippings()
                .OrderBy(i => i.Name)
                .ToSelectableList();

            ViewData["Countries"] = this.Actor.QueryCountries()
                .ToSelectableList();

            ViewData["InvoiceCountries"] = this.Actor.QueryCountries()
                .ToSelectableList();




            return View(ObjectContainer.CreateInstance<IOrder>());
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Create(IOrder order)
        {
            if (ModelState.IsValid)
            {
                this.Actor.Post(order);

                return Json(true);
            }
            else
            {

                return Json(new { Message = ModelState.GetErrorMessages() });
            }
        }

        public ActionResult SearchProducts(string keyword)
        {
            var list = this.Actor
                .QueryProducts()
                .Where(i => i.Name.Contains(keyword) || i.Id.ToString().Contains(keyword))
                .SelectMany(i => i.SaleItems.Select(m => new
                {
                    ProductId = i.Id,
                    ProductName = i.Name,
                    Variations = m.ProductVariations.Select(n => new { Name = n.Variation.Name, n.Value }).ToArray(),
                    UnitPrice = m.RetailPrice,
                    SaleItemId = m.Id,
                    SKU = m.SKU,
                    CustomFields = m.Product.ProductCustomFields.Select(n => new { Name = n.CustomField.Name, Value = n.Value }).ToArray()
                }))
                .OrderByDescending(i => i.ProductId)
                .ThenByDescending(i => i.SaleItemId)
                .Take(Configuration.PageSize)
                .ToArray();

            return Json(new { Data = list, Culture = Thread.CurrentThread.CurrentCulture.Name }, JsonRequestBehavior.AllowGet);
        }

        public ActionResult SearchCustomers(string keyword)
        {
            var query = this.Actor
                .QueryCustomers();


            int id;

            if (int.TryParse(keyword, out id))
            {
                query = query.Where(i => i.Id == id);
            }
            else
            {
                if (!String.IsNullOrEmpty(keyword))
                {
                    query = query.Where(i => i.UserName.Contains(keyword)
                      || i.FirstName.Contains(keyword)
                      || i.LastName.Contains(keyword)
                      || (i.FirstName + " " + i.LastName).Contains(keyword)

                      || i.MailAddress.Contains(keyword));
                }
            }

            var list = query
                .OrderByDescending(i => i.Id)
                .Select(i => new
                 {
                     Id = i.Id,
                     Name = i.FirstName + " " + i.MiddleName + " " + i.LastName,
                     Mail = i.MailAddress,
                     Telephone = i.Telphone,
                     //Country = i.Country == null ? "" : i.Country.CountryName,
                     i.Country,
                     City = i.City,
                     AddressBooks = i.Addresses.Select(n => new
                     {
                         Name = n.FirstName + " " + n.LastName,
                         n.Id,
                         n.FirstName,
                         n.LastName,
                         CountryCode = n.Country.CountryCode,
                         CountryName = n.Country.CountryName,
                         n.City,
                         n.Address1,
                         n.Address2,
                         n.Postcode,
                         n.State,
                         n.Phone
                     }).ToArray()
                 })
                 .Take(Configuration.PageSize)
                 .ToArray();

            return Json(list, JsonRequestBehavior.AllowGet);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Calculate(IOrder order)
        {
            this.Actor.UpdateTotal(order);


            return Json(new
            {
                Data = new
                {
                    SubTotal = order.SubTotal.ToString("c"),
                    ShippingAndHandling = (order.ShippingCost + order.PaymentMethodCost).ToString("c"),
                    GrandTotal = (order.SubTotal + order.ShippingCost + order.PaymentMethodCost).ToString("c"),
                    TotalPaid = (order.SubTotal + order.ShippingCost + order.PaymentMethodCost + order.TotalTaxCost).ToString("c"),
                    TotalRefunded = (order.TotalDiscount).ToString("c"),
                    TotalDue = (order.SubTotal + order.ShippingCost + order.PaymentMethodCost + order.TotalTaxCost - order.TotalDiscount).ToString("c")
                }
            });
        }

        [HttpPost]
        public ActionResult ChangeStatus(IOrder order, OrderStatus status)
        {
            try
            {
                order.ChangeStatus(status);
            }
            catch (ArgumentNullException)
            {
                return Json(new { Message = "The order is invalid.".Localize() });
            }
            catch (KeyNotFoundException)
            {
                return Json(new { Message = "The order id cannot be found.".Localize() });
            }

            return Json(true);

        }

        [HttpPost]
        public ActionResult UpdateRemark(IOrder order, string remark)
        {
            try
            {
                order.UpdateRemark(remark);
            }
            catch (ArgumentNullException)
            {
                return Json(new { Message = "The order is invalid.".Localize() });
            }
            catch (KeyNotFoundException)
            {
                return Json(new { Message = "The order id cannot be found.".Localize() });
            }

            return Json(true);
        }
    }

}
